import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Work, WorkDocument } from '@/work/schemas/work.schema';
import LegoComponents from 'lego-components';
import { renderToString, renderToNodeStream } from 'vue/server-renderer';
import { pipeline as pipelineCallback } from 'node:stream';
import { promisify } from 'node:util';
import { createSSRApp } from 'vue';
import { ValidationException } from '@/common/exceptions/custom-exception';

@Injectable()
export class UtilService {
  constructor(@InjectModel(Work.name) private workModel: Model<WorkDocument>) {}

  propsToStyle(props = {}) {
    const keys = Object.keys(props);
    const styleArr = keys.map((key) => {
      // fontSize -> font-size
      const formatKey = key.replace(
        /[A-Z]/g,
        (c) => `-${c.toLocaleLowerCase()}`,
      );
      const value = props[key];
      return `${formatKey}: ${value}`;
    });
    return styleArr.join(';');
  }

  px2vw(components = []) {
    // '10px' '9.5px'
    const reg = /^(\d+(\.\d+)?)px$/;
    components.forEach((component) => {
      const props = component.props || {};
      Object.keys(props).forEach((key) => {
        const val = props[key];
        if (typeof val !== 'string') {
          return;
        }
        if (reg.test(val) === false) {
          return;
        }
        const arr = val.match(reg) || [];
        const numStr = arr[1];
        const num = parseFloat(numStr);
        const vmNum = (num / 375) * 100;
        props[key] = `${vmNum.toFixed(2)}vw`;
      });
    });
  }

  async renderToPageData(query: { uuid: string }) {
    const work = await this.workModel.findOne(query).lean();
    if (!work) {
      throw new ValidationException('workNoExsitFail');
    }
    const { title, desc, content } = work;
    let _content = content;
    if (typeof content === 'string') {
      _content = JSON.parse(content);
    }
    // content 是个字符串，改成obj
    this.px2vw(_content && _content.components);
    const vueApp = createSSRApp({
      data: () => {
        return {
          components: (_content && _content.components) || [],
        };
      },
      template: '<final-page :components="components"></final-page>',
    });
    vueApp.use(LegoComponents);
    const html = await renderToString(vueApp);
    const bodyStyle = this.propsToStyle(_content && _content.props);
    return { title, desc, html, bodyStyle };
  }
}
